/**
 * \file
 *
 * \brief 测试程序，演示各功能
 * 
 * \author 高明飞
 *
 * \date 2015-09-12
 *
 * \note 系统时钟频率配置为33.1776MHz;\n
 *       主程序使用状态机完成
 *
 * 修改记录：\n
 *
 * 2015-10-06 :\n
 *   -修正UART初始化函数Bug，在初始化函数中添加TI = 1
 * 			
 */

#include "main.h"

/** 程序基本参数 */
struct ProParaStruct
{
	XFSSpeakers TTSSpeaker; /**< 发音人 */
	uint8_t TTSVolume;      /**< 当前音量 */
	uint8_t TTSSpeed;       /**< 当前语速 */
	uint8_t TTSTune;        /**< 当前音调 */

	uint8_t TTSIndex;       /**< 当前目录索引值 */
	uint8_t TTSMode;        /**< 当前播放模式 */
};

/** FSM 状态 */
typedef enum
{
	INIT,   /**< 初始状态 */
  IDLE,   /**< 空闲状态 */
  BUSY,   /**< 忙碌状态（正在发音中） */
  SETTING /**< 参数设置状态 */
} FSM_STATE;
static FSM_STATE ProgramState = INIT;

/**
 * 主函数
 */
int main()
{
	struct ProParaStruct ProPara = {XF_XiaoYan,5,5,5,1,0};
	
	Init();

	for(;;)
	{
		/* 依次扫描键盘、数码管及LED */
		KeyBoard_Scan();
	  Digitron_Refresh();
		LED_Refresh();
		
		/* FSM */
		switch(ProgramState)
		{
/*--------- INIT ---------*/
			case INIT:
			/* 检测按键 */
			switch(KeyBoard_State)
			{
				case 0x23:				
				ProPara.TTSMode = 0;
				ProPara.TTSIndex = 1;
				ProgramState = IDLE;
				UARTSendString("0x23 Pushed!   INIT->IDLE\r\n");
				break;
				
				case 0x33:
				ProPara.TTSMode = 1;
				ProPara.TTSIndex = 1;
				ProgramState = IDLE;
				UARTSendString("0x33 Pushed!   INIT->IDLE\r\n");
				break;
				
				case 0x22:
				ProPara.TTSMode = 2;
				ProPara.TTSIndex = 1;
				ProgramState = IDLE;
				UARTSendString("0x22 Pushed!   INIT->IDLE\r\n");
				break;
				
				case 0x32:
				ProPara.TTSMode = 3;
				ProPara.TTSIndex = 1;
				ProgramState = IDLE;
				UARTSendString("0x32 Pushed!   INIT->IDLE\r\n");
				break;
				
				case 0x41:
				ProgramState = SETTING;
				UARTSendString("0x41 Pushed!   INIT->SETTING\r\n");
				break;
				
				default:
				break;
			}
			
			break;

/*--------- IDLE ---------*/			
			case IDLE:
			/* 检测按键 */
			switch(KeyBoard_State)
			{
				/* 模式切换 */
				case 0x23:
				ProPara.TTSMode = 0;
				ProPara.TTSIndex = 1;
				break;
				
				case 0x33:
				ProPara.TTSMode = 1;
				ProPara.TTSIndex = 1;
				break;
				
				case 0x22:
				ProPara.TTSMode = 2;
				ProPara.TTSIndex = 1;
				break;
				
				case 0x32:
				ProPara.TTSMode = 3;
				ProPara.TTSIndex = 1;	
				break;
				
				/* 序号增减 */
				case 0x14:
				if(ProPara.TTSIndex > 1)
					ProPara.TTSIndex--;
				break;
				
				case 0x15:
				switch(ProPara.TTSMode)
				{
					case 0:
					if(ProPara.TTSIndex < 11)
						ProPara.TTSIndex++;
					break;
					
					case 3:
					if(ProPara.TTSIndex < 30)
						ProPara.TTSIndex++;
					break;
					
					case 1:
					case 2:
					if(ProPara.TTSIndex < 25)
						ProPara.TTSIndex++;
					break;
					
					default:
					break;
				}
				break;
				
				/* 开始播放 */
				case 0x47:
				ShutDown = 1;
				ProgramState = BUSY;
				UARTSendString("Start!   IDLE->BUSY\r\n");
				switch(ProPara.TTSMode)
				{
					/* 语音 */
					case 0:
					if(XFS5152CE_Start(SoundList[ProPara.TTSIndex - 1], SoundLength[ProPara.TTSIndex - 1]) == XFSOK)
						UARTSendString("XFS5152CE OK!\r\n");
					else
						UARTSendString("XFS5152CE Failed!\r\n");
					break;
					
					/* 信息提示音 */
					case 1:
					if(XFS5152CE_Msg_Tone(ProPara.TTSIndex) == XFSOK)
						UARTSendString("XFS5152CE OK!\r\n");
					else
						UARTSendString("XFS5152CE Failed!\r\n");
					break;
					
					/* 铃声提示音 */
					case 2:
					if(XFS5152CE_Ring_Tone(ProPara.TTSIndex) == XFSOK)
						UARTSendString("XFS5152CE OK!\r\n");
					else
						UARTSendString("XFS5152CE Failed!\r\n");
					break;
					
					/* 警报提示音 */
					case 3:
					if(XFS5152CE_Warning_Tone(ProPara.TTSIndex) == XFSOK)
						UARTSendString("XFS5152CE OK!\r\n");
					else
						UARTSendString("XFS5152CE Failed!\r\n");
					break;
					
					default:
					break;
				}
				break;
				
				/* 转到设置 */
				case 0x41:
				ProgramState = SETTING;
				UARTSendString("IDLE->SETTING\r\n");
				break;
				
				default:
				break;
			}
			
			/* 更新LED及数码管显示 */
			LED_OFF_Pink();
			
			Digitron_Clear();
			DigitronDisplay[5] = ProPara.TTSMode;
			DigitronDisplay[0] = ProPara.TTSIndex % 10;
			if(ProPara.TTSIndex > 9)
				DigitronDisplay[1] = ProPara.TTSIndex / 10;
			
			switch(ProPara.TTSMode)
			{
				case 0:
				LEDValue[0] |= 0x08; 
				break;
				
				case 1:
				LEDValue[1] |= 0x08;
				break;
	
				case 2:	
				LEDValue[0] |= 0x04;
				break;
				
				case 3:
				LEDValue[1] |= 0x04;
				break;
				
				default:
				break;
			}
			break;

/*--------- BUSY ---------*/			
			case BUSY:
			if(XFS5152CE_BUSY == 0)
			{
				ShutDown = 0;
				ProgramState = IDLE;
				UARTSendString("End!   BUSY->IDLE\r\n");
			}
			break;

/*--------- SETTING ---------*/
			case SETTING:
			/* 检测按键 */
			switch(KeyBoard_State)
			{
				case 0x23:				
				ProPara.TTSMode = 0;
				ProPara.TTSIndex = 1;
				ProgramState = IDLE;
				UARTSendString("0x23 Pushed!   SETTING->IDLE\r\n");
				break;
				
				case 0x33:
				ProPara.TTSMode = 1;
				ProPara.TTSIndex = 1;
				ProgramState = IDLE;
				UARTSendString("0x33 Pushed!   SETTING->IDLE\r\n");
				break;
				
				case 0x22:
				ProPara.TTSMode = 2;
				ProPara.TTSIndex = 1;
				ProgramState = IDLE;
				UARTSendString("0x22 Pushed!   SETTING->IDLE\r\n");
				break;
				
				case 0x32:
				ProPara.TTSMode = 3;
				ProPara.TTSIndex = 1;
				ProgramState = IDLE;
				UARTSendString("0x32 Pushed!   SETTING->IDLE\r\n");
				break;
				
				/* 参数增减 */
				case 0x11:
				if(ProPara.TTSVolume < 9)
					ProPara.TTSVolume++;
				if(XFS5152CE_Volume(ProPara.TTSVolume) == XFSOK)
					UARTSendString("XFS5152CE Set Volume OK!\r\n");
				else
				{
					ProPara.TTSVolume--;
					UARTSendString("XFS5152CE Set Volume Failed!\r\n");
				}
				while(XFS5152CE_BUSY == 1);
				break;
				
				case 0x10:
				if(ProPara.TTSSpeed < 9)
					ProPara.TTSSpeed++;
				if(XFS5152CE_Speed(ProPara.TTSSpeed) == XFSOK)
					UARTSendString("XFS5152CE Set Speed OK!\r\n");
				else
				{
					ProPara.TTSSpeed--;
					UARTSendString("XFS5152CE Set Speed Failed!\r\n");
				}
				while(XFS5152CE_BUSY == 1);
				break;
				
				case 0x20:
				if(ProPara.TTSTune < 9)
					ProPara.TTSTune++;
				if(XFS5152CE_Tune(ProPara.TTSTune) == XFSOK)
					UARTSendString("XFS5152CE Set Tune OK!\r\n");
				else
				{
					ProPara.TTSTune--;
					UARTSendString("XFS5152CE Set Tune Failed!\r\n");
				}
				while(XFS5152CE_BUSY == 1);
				break;
				
				case 0x13:
				if(ProPara.TTSVolume > 0)
					ProPara.TTSVolume--;
				if(XFS5152CE_Volume(ProPara.TTSVolume) == XFSOK)
					UARTSendString("XFS5152CE Set Volume OK!\r\n");
				else
				{
					ProPara.TTSVolume++;
					UARTSendString("XFS5152CE Set Volume Failed!\r\n");
				}
				while(XFS5152CE_BUSY == 1);
				break;
				
				case 0x12:
				if(ProPara.TTSSpeed > 0)
					ProPara.TTSSpeed--;
				if(XFS5152CE_Speed(ProPara.TTSSpeed) == XFSOK)
					UARTSendString("XFS5152CE Set Speed OK!\r\n");
				else
				{
					ProPara.TTSSpeed++;
					UARTSendString("XFS5152CE Set Speed Failed!\r\n");
				}
				while(XFS5152CE_BUSY == 1);
				break;
				
				case 0x30:
				if(ProPara.TTSTune > 0)
					ProPara.TTSTune--;
				if(XFS5152CE_Tune(ProPara.TTSTune) == XFSOK)
					UARTSendString("XFS5152CE Set Tune OK!\r\n");
				else
				{
					ProPara.TTSTune++;
					UARTSendString("XFS5152CE Set Tune Failed!\r\n");
				}
				while(XFS5152CE_BUSY == 1);
				break;
				
				/* 发音人 */
				case 0x24:
				ProPara.TTSSpeaker = XF_XiaoYan;
				if(XFS5152CE_Speaker(ProPara.TTSSpeaker) == XFSOK)
					UARTSendString("XFS5152CE Set Speaker OK!\r\n");
				else
					UARTSendString("XFS5152CE Set Speaker Failed!\r\n");
				while(XFS5152CE_BUSY == 1);
				break;
				
				case 0x34:
				ProPara.TTSSpeaker = XF_Xujiu;
				if(XFS5152CE_Speaker(ProPara.TTSSpeaker) == XFSOK)
					UARTSendString("XFS5152CE Set Speaker OK!\r\n");
				else
					UARTSendString("XFS5152CE Set Speaker Failed!\r\n");
				while(XFS5152CE_BUSY == 1);
				break;
				
				case 0x25:
				ProPara.TTSSpeaker = XF_XuDuo;
				if(XFS5152CE_Speaker(ProPara.TTSSpeaker) == XFSOK)
					UARTSendString("XFS5152CE Set Speaker OK!\r\n");
				else
					UARTSendString("XFS5152CE Set Speaker Failed!\r\n");
				while(XFS5152CE_BUSY == 1);
				break;
				
				case 0x36:
				ProPara.TTSSpeaker = XF_XiaoPing;
				if(XFS5152CE_Speaker(ProPara.TTSSpeaker) == XFSOK)
					UARTSendString("XFS5152CE Set Speaker OK!\r\n");
				else
					UARTSendString("XFS5152CE Set Speaker Failed!\r\n");
				while(XFS5152CE_BUSY == 1);
				break;
				
				case 0x35:
				ProPara.TTSSpeaker = XF_Donald;
				if(XFS5152CE_Speaker(ProPara.TTSSpeaker) == XFSOK)
					UARTSendString("XFS5152CE Set Speaker OK!\r\n");
				else
					UARTSendString("XFS5152CE Set Speaker Failed!\r\n");
				while(XFS5152CE_BUSY == 1);
				break;
				
				case 0x26:
				ProPara.TTSSpeaker = XF_XuXiaobao;
				if(XFS5152CE_Speaker(ProPara.TTSSpeaker) == XFSOK)
					UARTSendString("XFS5152CE Set Speaker OK!\r\n");
				else
					UARTSendString("XFS5152CE Set Speaker Failed!\r\n");
				while(XFS5152CE_BUSY == 1);
				break;
				
				default:
				break;
			}
			
			/* 更新LED及数码管显示 */
			LED_OFF_Pink();
			LED_OFF_Green();
			
			Digitron_Clear();
			DigitronDisplay[5] = 0x0C;
			DigitronDisplay[4] = ProPara.TTSVolume;
			DigitronDisplay[2] = ProPara.TTSSpeed;
			DigitronDisplay[0] = ProPara.TTSTune;

			switch(ProPara.TTSSpeaker)
			{
				case XF_XiaoYan:
				LEDValue[0] |= 0x10; 	
				break;
				
				case XF_Xujiu:
				LEDValue[1] |= 0x10; 	
				break;
				
				case XF_XuDuo:
				LEDValue[0] |= 0x20; 	
				break;
				
				case XF_XiaoPing:
				LEDValue[1] |= 0x40; 	
				break;
				
				case XF_Donald:
				LEDValue[1] |= 0x20; 	
				break;
				
				case XF_XuXiaobao:
				LEDValue[0] |= 0x40; 	
				break;
				
				default:
				break;
			}
			break;
			
			default:
			break;
		}
	}
}


/**
 * 系统初始化函数
 */
static void Init(void)
{
	InitUART();
	
	/* ShutDown 推挽输出 */
	P3M0 |= 0x20;
	ShutDown = 0;
	
	UARTSendString("Program Begins~~\r\n");
	
	
	/* 初始化TTS芯片 */
	while(XFS5152CE_Init() != XFSOK)
	{
		UARTSendString("XFS5152CE Init Failed, Retry.\r\n");
	}
	UARTSendString("XFS5152CE Init OK!\r\n");
	
	/* 数码管显示 Hello */
	DigitronDisplay[0] = 0x00;
	DigitronDisplay[1] = 0x0E;
	DigitronDisplay[2] = 0x0E;
	DigitronDisplay[3] = 0x0B;
	DigitronDisplay[4] = 0x0D;
	
	/* LED指示灯初始化 */
	LEDValue[0] = 0x10;
}


/**
 * UART初始化
 *
 * \note 115200bps@33.1776MHz
 *
 */
static void InitUART(void)
{
	ACC = P_SW1;
	ACC &= ~(0x40 | 0x80);      //S1_S0=0 S1_S1=0
	P_SW1 = ACC;                //(P3.0/RxD, P3.1/TxD)
	
	SCON = 0x50;		//8位数据,可变波特率
	AUXR |= 0x40;		//定时器1时钟为Fosc,即1T
	AUXR &= 0xFE;		//串口1选择定时器1为波特率发生器
	TMOD &= 0x0F;		//设定定时器1为16位自动重装方式
	TL1 = 0xB8;		  //设定定时初值
	TH1 = 0xFF;		  //设定定时初值
	TR1 = 1;		    //启动定时器1
	ES = 1;         //使能串口中断
	EA = 1;
	
	TI = 1;         // !!!为配合UARTSendData使用，此处必须要先将TI置为1
}


/**
 * 熄灭粉红按钮对应LED
 */
static void LED_OFF_Pink(void)
{
	LEDValue[0] &= ~0x0C;
	LEDValue[1] &= ~0x0C;
}

/**
 * 熄灭绿色按钮对应LED
 */
static void LED_OFF_Green(void)
{
	LEDValue[0] &= ~0x70;
	LEDValue[1] &= ~0x70;
}

/**
 * 清空数码管显示
 */
static void Digitron_Clear(void)
{
	DigitronDisplay[0] = 0xFF;
	DigitronDisplay[1] = 0xFF;
	DigitronDisplay[2] = 0xFF;
	DigitronDisplay[3] = 0xFF;
	DigitronDisplay[4] = 0xFF;
	DigitronDisplay[5] = 0xFF;
}

/**
 * UART ISR
 */
void UART_ISR_Handle() interrupt 4 using 3
{
	static char isp_cnt = 0;
	
	/* 关中断 */
	ES=0;
	
	/* 串口中断处理 */
	if(RI)
	{
		/* 此处必须要手动清标志位 */
		RI=0;
		
		/* ISP Reset */
		if(SBUF==0x7F)
			isp_cnt++;
		else
			isp_cnt = 0;
		if(isp_cnt > 25)
			IAP_CONTR |= 0x60;	
		
	}
	
	/* 重新使能中断 */
	ES=1;
}

